#include "aceMesh_utils.h"
//#include "args.h"
#include <sys/time.h>
#include "am_machine.h"
#ifdef TARG_SW9
extern __uncached volatile unsigned long con_status;
extern __uncached volatile unsigned long con_dest_ptr;
//extern __uncached volatile unsigned long con_graph;
//extern __uncached volatile int spawn_status[MULTI_STATUS];
extern __uncached volatile unsigned long con_src_ptr;
extern __uncached volatile unsigned long con_task_ptr[MULTI_TASK];
extern __uncached volatile unsigned long temp_task[MULTI_TASK];
extern __uncached volatile unsigned long con_task_num;
extern int cgid;
extern int total_num_threads;
extern __uncached unsigned long block_time,block_temp;
#ifdef GS_AGENT
#define thread_id 0
#else
#define thread_id total_num_threads-1
#endif

#endif

long long tick_count_now()
{
    long long  my_count;
    struct timeval start;
    gettimeofday(&start,NULL);
    my_count=start.tv_sec+start.tv_usec;
    return my_count;
}

unsigned long rpcc()
{
  unsigned long time;
  asm("rtc %0":"=&r"(time)::"memory");
  return time;
}


//! Table of primes used by fast random-number generator (FastRandom).
/** Also serves to keep anything else from being placed in the same
    cache line as the global data items preceding it. */
 static const unsigned Primes[] = { 
    0x9e3779b1, 0xffe6cc59, 0x2109f6dd, 0x43977ab5,
    0xba5703f5, 0xb495a877, 0xe1626741, 0x79695e6b,
    0xbc98c09f, 0xd5bee2b3, 0x287488f9, 0x3af18231,
    0x9677cd4d, 0xbe3a6929, 0xadc6a877, 0xdcf0674b,
    0xbe4d6fe9, 0x5f15e201, 0x99afc3fd, 0xf3f16801,
    0xe222cfff, 0x24ba5fdb, 0x0620452d, 0x79f149e3,
    0xc8b93f49, 0x972702cd, 0xb07dd827, 0x6c97d5ed,
    0x085a3d61, 0x46eb5ea7, 0x3d9910ed, 0x2e687b5b,
    0x29609227, 0x6eb081f1, 0x0954c4e1, 0x9d114db9,
    0x542acfa9, 0xb3e6bd7b, 0x0742d917, 0xe9f3ffa7,
    0x54581edb, 0xf2480f45, 0x0bb9288f, 0xef1affc7,
    0x85fa0ca7, 0x3ccc14db, 0xe6baf34b, 0x343377f7,
    0x5ca19031, 0xe6d9293b, 0xf0a9f391, 0x5d2e980b,
    0xfc411073, 0xc3749363, 0xb892d829, 0x3549366b,
    0x629750ad, 0xb98294e5, 0x892d9483, 0xc235baf3,
    0x3d2402a3, 0x6bdef3c9, 0xbec333cd, 0x40c9520f
 };

unsigned GetPrime ( unsigned seed ) {
    return Primes[seed%(sizeof(Primes)/sizeof(Primes[0]))];
}



void my_mutex_lock(volatile int* my_lock)
{
#ifdef TARG_SW5
#ifdef MUTEX_BASIC
    unsigned int __addr,__tmpi;
    __asm__ __volatile__(
        "        memb\n"
        "        ldi      %1,%2\n"
        "1:      ldw_inc  %0,0(%1)\n"
        "        bne      %0,1b\n"
        "        memb\n"
      : "=&r"  (__tmpi),
        "=&r"  (__addr)
      : "m" (*my_lock)
      : "memory");
    return;
#else
    unsigned int __tmp = 0;
    unsigned int __cnt;
    __asm__ __volatile__ (
    "0:     ldw     %[__tmp], %[my_lock]\n"
    "       beq     %[__tmp], 2f\n"
    "       ldi     %[__cnt], 50\n"
    "       sll     %[__cnt], 4, %[__cnt]\n"
    "1:     subw    %[__cnt], 1, %[__cnt]\n"
    "       bne     %[__cnt], 1b\n"
    "       br      0b\n"
    "2:     ldw_inc    %[__tmp], %[my_lock]\n"
    "       bne     %[__tmp], 0b\n"
    "       memb    \n"
    "       br      3f\n"
    "3:     unop    \n"
    : [__tmp] "=&r"(__tmp), [__cnt] "=&r"(__cnt)
    : [my_lock] "m"(*(my_lock))
    : "memory");
    return;
#endif
#elif TARG_SW9
    my_h2ldm(con_src_ptr,thread_id,cgid,unsigned long)=(unsigned long)my_lock;
   // con_src_ptr=(unsigned long)my_lock;
    asm volatile("memb\n");
    my_h2ldm(con_status,thread_id,cgid,int)=1;
    //my_h2ldm(con_status,total_num_threads-1,cgid,int)=1;
    asm volatile("memb\n");
    block_temp=rpcc();
    while(my_h2ldm(con_status,thread_id,cgid,int));
    block_time+=rpcc()-block_temp;
    asm volatile("memb\n");
    return ;
#endif
}
void my_mutex_unlock(volatile int* my_lock)
{
#ifdef TARG_SW5
#ifdef MUTEX_BASIC
    unsigned int __addr ;
    __asm__ __volatile__(
        "        memb\n"
        "        ldi      %0,%1\n"
        "        stw  $31,0(%0)\n"
        "        memb\n"
      : "=&r"  (__addr)
      : "m" (*my_lock)
      : "memory");
    return;
#else
    unsigned int __tmp = 0;
    __asm__ __volatile__ (
    "       memb    \n"
    "       mov     0, %[__tmp]\n"
    "       stw     %[__tmp], %[my_lock]\n"
    : [__tmp] "=&r"(__tmp)
    : [my_lock] "m"(*(my_lock))
    : "memory"
    );
    return;
#endif

#elif TARG_SW9
    #ifdef UNBLOCK_AGENT
    my_h2ldm(con_src_ptr,thread_id,cgid,unsigned long)=(unsigned long)my_lock;
   // con_src_ptr=(unsigned long)my_lock;
   asm volatile("memb\n");
   // con_status=4;
    my_h2ldm(con_status,thread_id,cgid,int)=4;
    asm volatile("memb\n");
    block_temp=rpcc();
   while(my_h2ldm(con_status,thread_id,cgid,int));
    block_time+=rpcc()-block_temp;
    asm volatile("memb\n");
    return ;
    #else
     unsigned int __tmp = 0;
      __asm__ __volatile__ (
         "       memb    \n"
         "       mov     0, %[__tmp]\n"
         "       stl     %[__tmp], %[my_lock]\n"
         : [__tmp] "=&r"(__tmp)
         : [my_lock] "m"(*(my_lock))
         : "memory"
         );
        return;
    #endif
#endif

}
#ifdef TARG_SW9
void my_atomic_add(volatile int* ref){
    //con_dest_ptr=(unsigned long)ref;
    my_h2ldm(con_src_ptr,thread_id,cgid,unsigned long)=(unsigned long)ref;
    asm volatile("memb\n");
    //con_status=2;
    my_h2ldm(con_status,thread_id,cgid,int)=2;
    asm volatile("memb\n");
     block_temp=rpcc();
    while(my_h2ldm(con_status,thread_id,cgid,int));
    block_time+=rpcc()-block_temp;
    asm volatile("memb\n");
    return ;
}
#ifndef MULTI_SPAWN
void my_spawn_to_id(struct task *t){
#else
void my_spawn_to_id(int num){ 
#endif
// while(con_status);
  //  asm volatile("memb\n");
    #ifdef MULTI_SPAWN
  
    int i;
    for(i=0;i<num;i++){
    my_h2ldm(con_task_ptr[i],thread_id,cgid,unsigned long)=(unsigned long)temp_task[i];
    //con_dest_ptr=(unsigned long)t;
   asm volatile("memb\n");
 }
    
    
    my_h2ldm(con_task_num,thread_id,cgid,int)=num;
   // my_h2ldm(spawn_status[iter],thread_id,cgid,int)=num;
    
     asm volatile("memb\n");
    //return ;
    #else
    my_h2ldm(con_src_ptr,thread_id,cgid,unsigned long)=(unsigned long)t;
    #endif
    asm volatile("memb\n");
   // while(con_status);
   
   // asm volatile("memb\n");
    //con_status=3;
  
  my_h2ldm(con_status,thread_id,cgid,int)=3;
    asm volatile("memb\n");
    block_temp=rpcc();
   while(my_h2ldm(con_status,thread_id,cgid,int));
    block_time+=rpcc()-block_temp;
    asm volatile("memb\n");
    
    return ;
}
void my_atomic_sub(volatile int* ref){
    
    my_h2ldm(con_src_ptr,thread_id,cgid,unsigned long)=(unsigned long)ref; 
    //con_dest_ptr=(unsigned long)ref;
    asm volatile("memb\n");
    //con_status=5;
    my_h2ldm(con_status,thread_id,cgid,int)=5;
    asm volatile("memb\n");
    block_temp=rpcc();
    while(my_h2ldm(con_status,thread_id,cgid,int));
     block_time+=rpcc()-block_temp;
    asm volatile("memb\n");
    return ;

}
#endif
